﻿using Algorithm.Check;
using Common;
using System;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using static Algorithm.Check.ExtensionForCRC16;

namespace T68Control.Procdure
{
    /// <summary>
    /// 64路IO继电器
    /// </summary>
    internal class PQW_IO
    {
        private static string deviceName = "继电器模块";
        private static SerialPort serialPort;

        //private static byte[] recvData;
        //private static readonly object locker = new object();
        [Conditional("DEVICE")]
        public static void Connect(string port, int baud = 9600)
        {
            serialPort = new SerialPort();
            serialPort.BaudRate = baud;
            serialPort.PortName = port;

            ManualResetEventSlim openCompletedEvent = new ManualResetEventSlim(false);
            Task.Run(() =>
            {
                serialPort.Open();
                openCompletedEvent.Set();
            });
            if (!openCompletedEvent.Wait(2000))
            {
                throw new Exception($"{deviceName}连接异常");
            }
        }

        public static void SetDO(int slaveId, int channel, bool status)
        {
            /* 01   05      00 05 ff 00         9c 3b
               站号 功能码  通道6 ff00打开通道  校验码
               01   05      00 05 00 00         dd cb
               站号 功能码  通道6 0000关闭通道  校验码 */
            Mylog.Debug($"[{deviceName}]SetDO slaveId[{slaveId}] channel[{channel}] status[{status}]");
            int tmp = channel - 1;
            byte[] data = new byte[] { (byte)slaveId, 05, (byte)((tmp & 0xff00) >> 8), (byte)(tmp & 0xff), (byte)(status ? 0xff : 0x00), 00 };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            byte[] recv = SendCmdAndWaitReturn(cmd);
            if (!recv.SequenceEqual(cmd))
            {
                Mylog.Debug($"[{deviceName}] SetDO错误，返回数据长度异常");
                throw new Exception($"[{deviceName}] SetDO错误，返回数据长度异常");
            }
        }

        public static void OffAll(int slaveId)
        {
            Mylog.Debug($"[{deviceName}] slaveId[{slaveId}] Off All");
            byte[] data = new byte[] { (byte)slaveId, 06, 00, 0x85, 00, 00 };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            byte[] recv = SendCmdAndWaitReturn(cmd);
            if (!recv.SequenceEqual(cmd))
            {
                Mylog.Debug($"[{deviceName}] OffAll错误，返回数据长度异常");
                throw new Exception($"[{deviceName}] OffAll错误，返回数据长度异常");
            }
        }

        public static bool GetDO(int slaveId, int channel)
        {
            bool status = false;
            int tmp = channel - 1;
            byte[] data = new byte[] { (byte)slaveId, 01, (byte)((tmp & 0xff00) >> 8), (byte)(tmp & 0xff), 0x0, 0x01 };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            byte[] recv = SendCmdAndWaitReturn(cmd);
            if (recv.Length != 6)
            {
                Mylog.Debug($"[{deviceName}] GetDO错误，返回数据与长度异常");
                throw new Exception($"[{deviceName}] GetDO错误，返回数据与长度异常");
            }
            status = (recv[3] & 0x01) == 0x01;
            Mylog.Debug($"[{deviceName}]GetDO slaveId[{slaveId}] channel[{channel}] status[{status}]");
            return status;
        }

        /// <summary>
        /// 设置波特率，重新上电生效
        /// </summary>
        /// <param name="slaveId"> 从机地址 </param>
        /// <param name="level">
        /// 波特率级别 0-4800 1-9600 2-14400 3-19200 4-38400 5-56000 6-57600 7-115200
        /// </param>
        public static void SetBaud(int slaveId, int level)
        {
            Mylog.Debug($"[{deviceName}]SetBaud slaveId[{slaveId}] level[{level}]");

            byte[] data = new byte[] { (byte)slaveId, 06, 00, 0x44, 0x00, (byte)level };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            byte[] recv = SendCmdAndWaitReturn(cmd);
            if (!recv.SequenceEqual(cmd))
            {
                Mylog.Debug($"[{deviceName}] SetBaud，返回数据长度异常");
                throw new Exception($"[{deviceName}] SetBaud，返回数据长度异常");
            }
        }

        /// <summary>
        /// 设置从机地址
        /// </summary>
        /// <param name="slaveId">    从机ID </param>
        /// <param name="newSlaveId"> 新的从机ID 从1开始 0为广播地址 </param>
        public static void SetSlaveId(int slaveId, int newSlaveId)
        {
        }

        private static byte[] SendCmdAndWaitReturn(byte[] cmd)
        {
            serialPort.DiscardInBuffer();
            Mylog.Debug($"[{deviceName}] sendCmd [{BitConverter.ToString(cmd).Replace('-', ' ')}]");
            serialPort.Write(cmd, 0, cmd.Length);
            Thread.Sleep(50);
            if (serialPort.BytesToRead > 0)
            {
                byte[] recv = new byte[serialPort.BytesToRead];
                serialPort.Read(recv, 0, recv.Length);
                Mylog.Debug($"[{deviceName}] recvCmd [{BitConverter.ToString(recv).Replace('-', ' ')}]");
                return recv;
            }
            throw new Exception($"[{deviceName}]未收到数据");
        }
    }
}